package impl

import (
	"context"
	"fmt"
	"gitee.com/hexug/go-tools/common/validate"
	"gitee.com/hexug/go-tools/logger"
	"gitee.com/hexug/kube-sync/apps/resource"
	appsv1 "k8s.io/api/apps/v1"
	batchv1 "k8s.io/api/batch/v1"
	batchv1beta1 "k8s.io/api/batch/v1beta1"
	corev1 "k8s.io/api/core/v1"
	rbacv1 "k8s.io/api/rbac/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"strings"
)

// TODO 为实现基于标签的搜索 待完善
func (s *svcImpl) ListDeploy(ctx context.Context, req *resource.ListDeployRequest) (map[string][]*appsv1.Deployment, error) {
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorw("validate err", "err", err, "req", req)
		return nil, err
	}
	if req.ClientSet == nil {
		logger.L().Errorw("k8s client is nil")
		return nil, fmt.Errorf("k8s client is nil")
	}
	dList := make(map[string][]*appsv1.Deployment)
	for _, namespace := range req.Namespace {
		dList[namespace] = []*appsv1.Deployment{}
		list, err := req.ClientSet.AppsV1().Deployments(namespace).List(ctx, metav1.ListOptions{})
		if err != nil {
			logger.L().Errorw("list resource err", "err", err, "namespace", namespace)
			return nil, err
		}
		for _, item := range list.Items {
			flag := false
			if dep, ok := req.ExcludeDeployNames[namespace]; ok {
				for _, exclude1 := range dep {
					if item.Name == exclude1 {
						flag = true
						break
					}
				}
				if flag {
					continue
				}
			}
			for _, exclude2 := range req.ExcludeDeployNames[""] {
				if item.Name == exclude2 {
					flag = true
					break
				}
			}
			if flag {
				continue
			}
			dList[namespace] = append(dList[namespace], &item)
		}
	}
	return dList, nil
}

// TODO 未实现基于标签的搜索 待完善
// TODO 未验证
func (s *svcImpl) ListWorkload(ctx context.Context, req *resource.ListWorkloadRequest) (*resource.ListWorkloadRespone, error) {
	if err := req.Validate(); err != nil {
		logger.L().Errorw("validate err", "err", err, "req", req)
		return nil, err
	}
	rep := resource.NewListWorkloadRespone()
	for _, namespace := range req.Namespace {

		// 获取Deployment
		listdep, err := req.ClientSet.AppsV1().Deployments(namespace).List(ctx, metav1.ListOptions{})
		if err != nil {
			logger.L().Errorw("list resource err", "err", err, "namespace", namespace)
			return nil, err
		}
		for _, item := range listdep.Items {
			flag := false
			if len(req.ExcludeWorkloads) > 0 {
				for _, excludewls := range req.ExcludeWorkloads {
					if (item.Name == excludewls.Workload || excludewls.Workload == "") &&
						(item.Namespace == excludewls.Namespace || excludewls.Namespace == "") &&
						(excludewls.WorkloadType == "Deployment" || excludewls.WorkloadType == "") {
						flag = true
						break
					}
				}
				if flag {
					continue
				}
			} else if len(req.IncludeWorkloads) > 0 {
				for _, includewls := range req.IncludeWorkloads {
					if (item.Name == includewls.Workload || includewls.Workload == "") &&
						(item.Namespace == includewls.Namespace || includewls.Namespace == "") &&
						(includewls.WorkloadType == "Deployment" || includewls.WorkloadType == "") {
						flag = true
						break
					}
				}
				if !flag {
					continue
				}
			}

			key := fmt.Sprintf("%s:Deployment:%s", namespace, item.Name)
			res := resource.NewWorkloadCore(namespace, item.Name, "Deployment")
			res.Workload = &item
			rep.AddWorkload(key, res)
		}

		// 获取StatefulSet
		liststfs, err := req.ClientSet.AppsV1().StatefulSets(namespace).List(ctx, metav1.ListOptions{})
		if err != nil {
			logger.L().Errorw("list resource err", "err", err, "namespace", namespace)
			return nil, err
		}

		for _, item := range liststfs.Items {
			flag := false
			if len(req.ExcludeWorkloads) > 0 {
				for _, excludewls := range req.ExcludeWorkloads {
					if (item.Name == excludewls.Workload || excludewls.Workload == "") &&
						(item.Namespace == excludewls.Namespace || excludewls.Namespace == "") &&
						(excludewls.WorkloadType == "StatefulSet" || excludewls.WorkloadType == "") {
						flag = true
						break
					}
				}
				if flag {
					continue
				}
			} else if len(req.IncludeWorkloads) > 0 {
				for _, includewls := range req.IncludeWorkloads {
					if (item.Name == includewls.Workload || includewls.Workload == "") &&
						(item.Namespace == includewls.Namespace || includewls.Namespace == "") &&
						(includewls.WorkloadType == "StatefulSet" || includewls.WorkloadType == "") {
						flag = true
						break
					}
				}
				if !flag {
					continue
				}
			}

			key := fmt.Sprintf("%s:StatefulSet:%s", namespace, item.Name)
			res := resource.NewWorkloadCore(namespace, item.Name, "StatefulSet")
			res.Workload = &item
			rep.AddWorkload(key, res)
		}

		// 获取Job
		listjobs, err := req.ClientSet.BatchV1().Jobs(namespace).List(ctx, metav1.ListOptions{})
		if err != nil {
			logger.L().Errorw("list resource err", "err", err, "namespace", namespace)
			return nil, err
		}

		for _, item := range listjobs.Items {
			flag := false
			if len(req.ExcludeWorkloads) > 0 {
				for _, excludewls := range req.ExcludeWorkloads {
					if (item.Name == excludewls.Workload || excludewls.Workload == "") &&
						(item.Namespace == excludewls.Namespace || excludewls.Namespace == "") &&
						(excludewls.WorkloadType == "Job" || excludewls.WorkloadType == "") {
						flag = true
						break
					}
				}
				if flag {
					continue
				}
			} else if len(req.IncludeWorkloads) > 0 {
				for _, includewls := range req.IncludeWorkloads {
					if (item.Name == includewls.Workload || includewls.Workload == "") &&
						(item.Namespace == includewls.Namespace || includewls.Namespace == "") &&
						(includewls.WorkloadType == "Job" || includewls.WorkloadType == "") {
						flag = true
						break
					}
				}
				if !flag {
					continue
				}
			}

			key := fmt.Sprintf("%s:Job:%s", namespace, item.Name)
			res := resource.NewWorkloadCore(namespace, item.Name, "Job")
			res.Workload = &item
			rep.AddWorkload(key, res)
		}

		// 获取CronJob
		listCronjobs, err := req.ClientSet.BatchV1().CronJobs(namespace).List(ctx, metav1.ListOptions{})
		if err != nil {
			logger.L().Warnw("list resource BatchV1  err,需要使用老版本", "err", err, "namespace", namespace)
			betaListCronjobs, err := req.ClientSet.BatchV1beta1().CronJobs(namespace).List(ctx, metav1.ListOptions{})
			if err != nil {
				logger.L().Errorw("list resource BatchV1beta1 err", "err", err, "namespace", namespace)
				return nil, err
			}
			for _, item := range betaListCronjobs.Items {
				flag := false
				if len(req.ExcludeWorkloads) > 0 {
					for _, excludewls := range req.ExcludeWorkloads {
						if (item.Name == excludewls.Workload || excludewls.Workload == "") &&
							(item.Namespace == excludewls.Namespace || excludewls.Namespace == "") &&
							(excludewls.WorkloadType == "CronJob" || excludewls.WorkloadType == "") {
							flag = true
							break
						}
					}
					if flag {
						continue
					}
				} else if len(req.IncludeWorkloads) > 0 {
					for _, includewls := range req.IncludeWorkloads {
						if (item.Name == includewls.Workload || includewls.Workload == "") &&
							(item.Namespace == includewls.Namespace || includewls.Namespace == "") &&
							(includewls.WorkloadType == "CronJob" || includewls.WorkloadType == "") {
							flag = true
							break
						}
					}
					if !flag {
						continue
					}
				}

				key := fmt.Sprintf("%s:CronJob:%s", namespace, item.Name)
				res := resource.NewWorkloadCore(namespace, item.Name, "CronJob")
				res.Workload = &item
				rep.AddWorkload(key, res)
			}
		}

		for _, item := range listCronjobs.Items {
			flag := false
			if len(req.ExcludeWorkloads) > 0 {
				for _, excludewls := range req.ExcludeWorkloads {
					if (item.Name == excludewls.Workload || excludewls.Workload == "") &&
						(item.Namespace == excludewls.Namespace || excludewls.Namespace == "") &&
						(excludewls.WorkloadType == "CronJob" || excludewls.WorkloadType == "") {
						flag = true
						break
					}
				}
				if flag {
					continue
				}
			} else if len(req.IncludeWorkloads) > 0 {
				for _, includewls := range req.IncludeWorkloads {
					if (item.Name == includewls.Workload || includewls.Workload == "") &&
						(item.Namespace == includewls.Namespace || includewls.Namespace == "") &&
						(includewls.WorkloadType == "CronJob" || includewls.WorkloadType == "") {
						flag = true
						break
					}
				}
				if !flag {
					continue
				}
			}

			key := fmt.Sprintf("%s:CronJob:%s", namespace, item.Name)
			res := resource.NewWorkloadCore(namespace, item.Name, "CronJob")
			res.Workload = &item
			rep.AddWorkload(key, res)
		}

		// 获取DaemonSet
		listDaemonSet, err := req.ClientSet.AppsV1().DaemonSets(namespace).List(ctx, metav1.ListOptions{})
		if err != nil {
			logger.L().Errorw("list resource err", "err", err, "namespace", namespace)
			return nil, err
		}

		for _, item := range listDaemonSet.Items {
			flag := false
			if len(req.ExcludeWorkloads) > 0 {
				for _, excludewls := range req.ExcludeWorkloads {
					if (item.Name == excludewls.Workload || excludewls.Workload == "") &&
						(item.Namespace == excludewls.Namespace || excludewls.Namespace == "") &&
						(excludewls.WorkloadType == "DaemonSet" || excludewls.WorkloadType == "") {
						flag = true
						break
					}
				}
				if flag {
					continue
				}
			} else if len(req.IncludeWorkloads) > 0 {
				for _, includewls := range req.IncludeWorkloads {
					if (item.Name == includewls.Workload || includewls.Workload == "") &&
						(item.Namespace == includewls.Namespace || includewls.Namespace == "") &&
						(includewls.WorkloadType == "DaemonSet" || includewls.WorkloadType == "") {
						flag = true
						break
					}
				}
				if !flag {
					continue
				}
			}

			key := fmt.Sprintf("%s:DaemonSet:%s", namespace, item.Name)
			res := resource.NewWorkloadCore(namespace, item.Name, "DaemonSet")
			res.Workload = &item
			rep.AddWorkload(key, res)
		}
	}
	return rep, nil
}

// TODO 待完成
func (s *svcImpl) GatherWorkload(ctx context.Context, req *resource.GatherWorkloadRequest) (*resource.ListWorkloadRespone, error) {
	//if err := req.Validate(); err != nil {
	//	logger.L().Errorw("validate err", "err", err, "req", req)
	//	return nil, err
	//}
	//dictNs := map[string]struct{}{}
	//for _, item := range req.Workloads {
	//	dictNs[item.Namespace] = struct{}{}
	//}
	//allWlNs := []string{}
	//for _, resNs := range req.Namespaces {
	//	if _, ok := dictNs[resNs]; !ok {
	//		allWlNs = append(allWlNs, resNs)
	//	}
	//}
	//lwlr := resource.NewListWorkloadRespone()
	//if len(allWlNs) > 0 {
	//	lwr := resource.NewListWorkloadRequest()
	//	lwr.AddNamespaces(allWlNs...)
	//	listw, err := s.ListWorkload(ctx, lwr)
	//	if err != nil {
	//		logger.L().Errorw("list resource err", "err", err, "namespaces", allWlNs)
	//		return nil, err
	//	}
	//	lwlr = listw
	//}
	//for _, item := range req.Workloads {
	//	wl, ok := lwlr.Workloads[item.Key()]
	//	if !ok {
	//		logger.L().Errorw("not found workload", "key", item.Key())
	//		continue
	//	}
	//	lwlr.Workloads[item.Key()] = wl
	//}
	panic("implement me")
}

// TODO 待完成
func (s *svcImpl) getWorkload(ctx context.Context, req *resource.ExcludeWorkloadCore, cli *kubernetes.Clientset) (*resource.WorkloadCore, error) {
	switch req.WorkloadType {
	case "Deployment":
		cli.AppsV1().Deployments(req.Namespace)
	case "DaemonSet":
	case "Job":
	case "CronJob":
	case "StatefulSet":
	default:
		return nil, fmt.Errorf("workload type %s not support", req.WorkloadType)
	}
	panic("implement me")
}

func (s *svcImpl) ListService(ctx context.Context, req *resource.ListServiceRequest) ([]*resource.ListServiceRespone, error) {
	if err := req.Validate(); err != nil {
		logger.L().Errorw("validate err", "err", err, "req", req)
		return nil, err
	}
	res := []*resource.ListServiceRespone{}
	for _, svc := range req.Services {
		// 拉取 namespace 下的所有 Service
		list, err := req.ClientSet.CoreV1().Services(svc.Namespace).List(ctx, metav1.ListOptions{})
		if err != nil {
			logger.L().Errorw("list resource err", "err", err, "namespace", svc.Namespace)
			return nil, err
		}

		for _, item := range list.Items {
			// 没有 selector 的 service 跳过
			if len(item.Spec.Selector) == 0 {
				continue
			}

			// 判断 Service 的 selector 是否是 Deploy 的 selector 子集
			isSubset := true
			for k, v := range item.Spec.Selector {
				if depVal, ok := svc.SelectorMap[k]; !ok || depVal != v {
					isSubset = false
					break
				}
			}

			if isSubset {
				lsr := resource.NewListServiceRespone()
				lsr.Services = &item
				lsr.Workload = svc.Workload
				lsr.Namespace = svc.Namespace
				lsr.WorkloadType = svc.WorkloadType
				res = append(res, lsr)
			}
		}
	}
	return res, nil
}

//func (s *svcImpl) FromDeployListService(ctx context.Context, req map[string][]*appsv1.Deployment, clientSet *kubernetes.Clientset) ([]*resource.ListServiceRespone, error) {
//	if len(req) <= 0 {
//		return nil, fmt.Errorf("请求不能为空")
//	}
//	lsr := resource.NewListServiceRequest()
//	lsr.ClientSet = clientSet
//	for namespace, deploys := range req {
//		if len(deploys) <= 0 {
//			continue
//		}
//		for _, deploy := range deploys {
//			reqCore := resource.NewServiceCore(namespace, deploy.Name, "Deployment")
//			reqCore.FromDeployAddSelectors(deploy)
//			lsr.AddServices(reqCore)
//		}
//	}
//	return s.ListService(ctx, lsr)
//}

func (s *svcImpl) FromWorkloadGetService(ctx context.Context, req *resource.FromWorkloadGetResourceRequest) ([]*resource.ListServiceRespone, error) {
	if err := req.Validate(); err != nil {
		logger.L().Errorw("validate err", "err", err, "req", req)
		return nil, err
	}

	lsr := resource.NewListServiceRequest()
	lsr.ClientSet = req.ClientSet

	for _, w := range req.Workloads {
		var ns, workloadName, workloadType string
		var selector map[string]string

		switch obj := w.(type) {
		case *appsv1.Deployment:
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "Deployment"
			if obj.Spec.Selector != nil {
				selector = obj.Spec.Selector.MatchLabels
			}
		case *appsv1.StatefulSet:
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "StatefulSet"
			if obj.Spec.Selector != nil {
				selector = obj.Spec.Selector.MatchLabels
			}
		case *appsv1.DaemonSet:
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "DaemonSet"
			if obj.Spec.Selector != nil {
				selector = obj.Spec.Selector.MatchLabels
			}
		default:
			continue
		}

		if len(selector) == 0 {
			continue
		}

		reqCore := resource.NewServiceCore(ns, workloadName, workloadType)
		reqCore.SelectorMap = selector

		// 可选：存一下原始 selector 的 key=value 形式
		for k, v := range selector {
			reqCore.Selectors = append(reqCore.Selectors, fmt.Sprintf("%s=%s", k, v))
		}

		lsr.AddServices(reqCore)
	}

	return s.ListService(ctx, lsr)
}

func (s *svcImpl) ListConfigMap(ctx context.Context, req *resource.ListConfigMapRequest) ([]*resource.ListConfigMapResponse, error) {
	if err := req.Validate(); err != nil {
		logger.L().Errorw("validate err", "err", err, "req", req)
		return nil, err
	}
	result := []*resource.ListConfigMapResponse{}
	for _, cmc := range req.ConfigMaps {
		rescm := resource.NewListConfigMapResponse(cmc)
		for _, name := range cmc.Names {
			cm, err := req.ClientSet.CoreV1().ConfigMaps(cmc.Namespace).Get(ctx, name, metav1.GetOptions{})
			if err != nil {
				logger.L().Errorw("get resource err", "err", err, "namespace", cmc.Namespace, "name", name)
				continue
			}
			for k, v := range cm.Data {
				cm.Data[k] = resource.RemoveEmptyLines(cmc.Namespace, name, k, v, cmc.WorkloadType, cmc.Workload)
			}
			rescm.SetConfigMap(cm)
		}
		result = append(result, rescm)
	}
	return result, nil
}

//func (s *svcImpl) FromDeployListConfigMap(ctx context.Context, req map[string][]*appsv1.Deployment, clientSet *kubernetes.Clientset) ([]*resource.ListConfigMapResponse, error) {
//	reqListConfigMap := resource.NewListConfigMapRequest()
//	reqListConfigMap.ClientSet = clientSet
//	for namespace, deploys := range req {
//		for _, deploy := range deploys {
//			names := resource.ExtractConfigMapNames(deploy)
//			reqListConfigMap.AddConfigMap(namespace, "Deployment", deploy.Name, names...)
//		}
//	}
//	return s.ListConfigMap(ctx, reqListConfigMap)
//}

func (s *svcImpl) FromWorkloadGetConfigMaps(ctx context.Context, req *resource.FromWorkloadGetResourceRequest) ([]*resource.ListConfigMapResponse, error) {
	if err := req.Validate(); err != nil {
		logger.L().Errorw("validate err", "err", err, "req", req)
		return nil, err
	}

	var results []*resource.ListConfigMapResponse

	if len(req.Workloads) == 0 {
		return results, nil
	}

	for _, w := range req.Workloads {
		var podSpec corev1.PodSpec
		var ns, workloadName, workloadType string

		switch obj := w.(type) {
		case *appsv1.Deployment:
			podSpec = obj.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "Deployment"
		case *appsv1.StatefulSet:
			podSpec = obj.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "StatefulSet"
		case *appsv1.DaemonSet:
			podSpec = obj.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "DaemonSet"
		case *batchv1.Job:
			podSpec = obj.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "Job"
		case *batchv1beta1.CronJob:
			podSpec = obj.Spec.JobTemplate.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "CronJob"
		case *batchv1.CronJob:
			podSpec = obj.Spec.JobTemplate.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "CronJob"
		default:
			continue
		}

		// 收集 ConfigMap 名称
		names := resource.ExtractConfigMapNamesFromPodSpec(&podSpec)

		if len(names) == 0 {
			continue
		}

		// 构造请求体
		cmCore := resource.NewConfigMapCore(ns, workloadType, workloadName, names...)
		listReq := resource.NewListConfigMapRequest()
		listReq.ClientSet = req.ClientSet
		listReq.ConfigMaps = []*resource.ConfigMapCore{cmCore}

		// 复用已有的 ListConfigMap
		res, err := s.ListConfigMap(ctx, listReq)
		if err != nil {
			logger.L().Errorw("list configmap err", "err", err, "workload", workloadName)
			continue
		}
		results = append(results, res...)
	}

	return results, nil
}

func (s *svcImpl) FromWorkloadGetRBAC(ctx context.Context, req *resource.FromWorkloadGetResourceRequest) (*resource.FromWorkloadGetRBACResponse, error) {
	results := resource.NewFromWorkloadGetRBACResponse()
	if len(req.Workloads) == 0 {
		return results, nil
	}
	if req.ClientSet == nil {
		logger.L().Errorw("k8s client is nil")
		return nil, fmt.Errorf("k8s client is nil")
	}
	for _, obj := range req.Workloads {
		var ns, name, saName, typ string

		switch o := obj.(type) {
		case *appsv1.Deployment:
			ns, name, typ = o.Namespace, o.Name, "Deployment"
			saName = o.Spec.Template.Spec.ServiceAccountName
		case *appsv1.StatefulSet:
			ns, name, typ = o.Namespace, o.Name, "StatefulSet"
			saName = o.Spec.Template.Spec.ServiceAccountName
		case *appsv1.DaemonSet:
			ns, name, typ = o.Namespace, o.Name, "DaemonSet"
			saName = o.Spec.Template.Spec.ServiceAccountName
		case *batchv1.Job:
			ns, name, typ = o.Namespace, o.Name, "Job"
			saName = o.Spec.Template.Spec.ServiceAccountName
		case *batchv1.CronJob:
			ns, name, typ = o.Namespace, o.Name, "CronJob"
			saName = o.Spec.JobTemplate.Spec.Template.Spec.ServiceAccountName
		case *batchv1beta1.CronJob:
			ns, name, typ = o.Namespace, o.Name, "CronJob"
			saName = o.Spec.JobTemplate.Spec.Template.Spec.ServiceAccountName
		default:
			// 不支持的类型
			logger.L().Errorw("unknown obj", "unknown:%T", obj)
			continue
		}

		key := fmt.Sprintf("%s:%s:%s", ns, typ, name)
		info := resource.NewRBACInfo()

		// 没有 SA 或者SA为 default 就跳过
		if saName == "" || saName == "default" {
			continue
		}

		// 获取 ServiceAccount
		sa, err := req.ClientSet.CoreV1().ServiceAccounts(ns).Get(ctx, saName, metav1.GetOptions{})
		if err != nil {
			continue
		}
		info.ServiceAccount = sa
		// RoleBinding
		rbs, err := req.ClientSet.RbacV1().RoleBindings(ns).List(ctx, metav1.ListOptions{})
		if err == nil {
			for _, rb := range rbs.Items {
				for _, subj := range rb.Subjects {
					if subj.Kind == "ServiceAccount" && subj.Name == sa.Name && subj.Namespace == sa.Namespace {
						info.RoleBindings = append(info.RoleBindings, &rb)
						if rb.RoleRef.Kind == "Role" {
							role, err := req.ClientSet.RbacV1().Roles(ns).Get(ctx, rb.RoleRef.Name, metav1.GetOptions{})
							if err == nil {
								info.Roles = append(info.Roles, role)
							}
						}
						if rb.RoleRef.Kind == "ClusterRole" {
							cr, err := req.ClientSet.RbacV1().ClusterRoles().Get(ctx, rb.RoleRef.Name, metav1.GetOptions{})
							if err == nil {
								info.ClusterRoles = append(info.ClusterRoles, cr)
							}
						}
					}
				}
			}
		}

		// ClusterRoleBinding
		crbs, err := req.ClientSet.RbacV1().ClusterRoleBindings().List(ctx, metav1.ListOptions{})
		if err == nil {
			for _, crb := range crbs.Items {
				for _, subj := range crb.Subjects {
					if subj.Kind == "ServiceAccount" && subj.Name == sa.Name && subj.Namespace == sa.Namespace {
						info.ClusterRBs = append(info.ClusterRBs, &crb)
						if crb.RoleRef.Kind == "ClusterRole" {
							cr, err := req.ClientSet.RbacV1().ClusterRoles().Get(ctx, crb.RoleRef.Name, metav1.GetOptions{})
							if err == nil {
								info.ClusterRoles = append(info.ClusterRoles, cr)
							}
						}
					}
				}
			}
		}
		results.AddRBACInfo(key, info)
	}
	return results, nil
}

func (s *svcImpl) FromWorkloadGetPVPVC(ctx context.Context, req *resource.FromWorkloadGetResourceRequest) (*resource.FromWorkloadGetPVPVCResponse, error) {
	results := resource.NewFromWorkloadGetPVPVCResponse()
	if err := req.Validate(); err != nil {
		logger.L().Errorw("validate err", "err", err, "req", req)
		return nil, err
	}
	if len(req.Workloads) == 0 {
		return results, nil
	}
	for _, w := range req.Workloads {
		var podSpec corev1.PodSpec
		var ns, workloadName, workloadType string
		workloadRes := resource.NewWorkloadVolumes()

		switch obj := w.(type) {
		case *appsv1.Deployment:
			podSpec = obj.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "Deployment"
		case *appsv1.StatefulSet:
			podSpec = obj.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "StatefulSet"
			// StatefulSet 还有 volumeClaimTemplates
			for _, vct := range obj.Spec.VolumeClaimTemplates {
				pvc, err := req.ClientSet.CoreV1().PersistentVolumeClaims(ns).Get(ctx, vct.Name, metav1.GetOptions{})
				if err == nil {
					workloadRes.AddPVC(pvc)
					if pvc.Spec.VolumeName != "" {
						pv, err := req.ClientSet.CoreV1().PersistentVolumes().Get(ctx, pvc.Spec.VolumeName, metav1.GetOptions{})
						if err == nil {
							workloadRes.AddPV(pv)
						}
					}
				}
			}
		case *appsv1.DaemonSet:
			podSpec = obj.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "DaemonSet"
		case *batchv1.Job:
			podSpec = obj.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "Job"
		case *batchv1.CronJob:
			podSpec = obj.Spec.JobTemplate.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "CronJob"
		case *batchv1beta1.CronJob:
			podSpec = obj.Spec.JobTemplate.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "CronJob"
		default:
			continue
		}

		key := fmt.Sprintf("%s:%s:%s", ns, workloadType, workloadName)

		// 遍历 podSpec.volumes，找出 PVC
		for _, vol := range podSpec.Volumes {
			if vol.PersistentVolumeClaim != nil {
				pvcName := vol.PersistentVolumeClaim.ClaimName
				pvc, err := req.ClientSet.CoreV1().PersistentVolumeClaims(ns).Get(ctx, pvcName, metav1.GetOptions{})
				if err != nil {
					fmt.Printf("warn: get PVC %s/%s failed: %v\n", ns, pvcName, err)
					continue
				}
				workloadRes.AddPVC(pvc)

				if pvc.Spec.VolumeName != "" {
					pv, err := req.ClientSet.CoreV1().PersistentVolumes().Get(ctx, pvc.Spec.VolumeName, metav1.GetOptions{})
					if err == nil {
						workloadRes.AddPV(pv)
					}
				}
			}
		}
		if len(workloadRes.PVCs) > 0 {
			results.AddWorkloadVolumes(key, workloadRes)
		}
	}
	return results, nil
}

func (s *svcImpl) FromWorkloadGetSecret(ctx context.Context, req *resource.FromWorkloadGetResourceRequest) (*resource.FromWorkloadGetSecretResponse, error) {
	if err := req.Validate(); err != nil {
		logger.L().Errorw("validate err", "err", err, "req", req)
		return nil, err
	}

	results := resource.NewFromWorkloadGetSecretResponse()

	for _, w := range req.Workloads {
		var podSpec corev1.PodSpec
		var ns, workloadName, workloadType string

		switch obj := w.(type) {
		case *appsv1.Deployment:
			podSpec = obj.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "Deployment"
		case *appsv1.StatefulSet:
			podSpec = obj.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "StatefulSet"
		case *appsv1.DaemonSet:
			podSpec = obj.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "DaemonSet"
		case *batchv1.Job:
			podSpec = obj.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "Job"
		case *batchv1.CronJob:
			podSpec = obj.Spec.JobTemplate.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "CronJob"
		case *batchv1beta1.CronJob:
			podSpec = obj.Spec.JobTemplate.Spec.Template.Spec
			ns, workloadName = obj.Namespace, obj.Name
			workloadType = "CronJob"
		default:
			continue
		}

		// 提取所有 Secret 名称
		secretNames := resource.ExtractSecretNamesFromPodSpec(&podSpec)
		key := fmt.Sprintf("%s:%s:%s", ns, workloadType, workloadName)
		core := resource.NewSecretCore(ns)
		// 去重
		seen := map[string]struct{}{}
		for _, name := range secretNames {
			if _, ok := seen[name]; ok {
				continue
			}
			seen[name] = struct{}{}

			secret, err := req.ClientSet.CoreV1().Secrets(ns).Get(ctx, name, metav1.GetOptions{})
			if err != nil {
				logger.L().Warnw("get secret err", "err", err, "namespace", ns, "name", name)
				continue
			}
			core.AddSecret(secret)
		}
		results.AddSecretCore(key, core)
	}
	return results, nil
}

// CheckNamespace 检查命名空间是否存在 会返回不存在的命名空间
func (s *svcImpl) CheckNamespace(ctx context.Context, req *resource.CheckNamespaceRequest) (*resource.CheckNamespaceResponse, error) {
	if err := req.Validate(); err != nil {
		logger.L().Errorw("validate err", "err", err, "req", req)
		return nil, err
	}
	rep := resource.NewCheckNamespaceResponse()
	nsList, err := req.ClientSet.CoreV1().Namespaces().List(ctx, metav1.ListOptions{})
	if err != nil {
		logger.L().Errorw("list namespace err", "err", err)
		return nil, err
	}
	nsDict := map[string]struct{}{}
	for _, ns := range nsList.Items {
		nsDict[ns.Name] = struct{}{}
	}
	for _, ns := range req.Namespaces {
		ns = strings.TrimSpace(ns)
		if ns == "" {
			continue // 跳过空字符串
		}

		if _, ok := nsDict[ns]; !ok {
			rep.AddNamespace(ns)
		}
	}
	return rep, nil
}

func (s *svcImpl) CreateNamespace(ctx context.Context, req *resource.CheckNamespaceRequest) error {
	if err := req.Validate(); err != nil {
		logger.L().Errorw("validate err", "err", err, "req", req)
		return err
	}
	nsRep, err := s.CheckNamespace(ctx, req)
	if err != nil {
		logger.L().Errorw("check namespace err", "err", err, "req", req)
		return err
	}
	for _, ns := range nsRep.Namespaces {
		ns = strings.TrimSpace(ns)
		if ns == "" {
			continue // 跳过空字符串
		}
		_, err = req.ClientSet.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{
			ObjectMeta: metav1.ObjectMeta{
				Name: ns,
			},
		}, metav1.CreateOptions{})
		if err != nil {
			logger.L().Errorw("create namespace err", "err", err, "namespace", ns)
			return err
		}
		logger.L().Debugw("create namespace", "namespace", ns)
	}
	return nil
}

func (s *svcImpl) CreateResource(ctx context.Context, req *resource.CreateResourceRequest) error {
	if err := req.Validate(); err != nil {
		logger.L().Errorw("validate err", "err", err, "req", req)
		return err
	}
	var err error
	for _, item := range req.Items {
		// 按 kind 进行类型分派
		switch item.ResourcesKind {
		case "Deployment":
			obj, ok := item.Resource.(*appsv1.Deployment)
			if !ok {
				logger.L().Errorw("转化Deployment资源失败", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			_, err = req.ClientSet.AppsV1().Deployments(item.Namespace).Create(ctx, obj, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorw("create Deployment resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			logger.L().Debugw("create Deployment resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
		case "StatefulSet":
			obj, ok := item.Resource.(*appsv1.StatefulSet)
			if !ok {
				logger.L().Errorw("转化StatefulSet资源失败", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			_, err = req.ClientSet.AppsV1().StatefulSets(item.Namespace).Create(ctx, obj, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorw("create StatefulSet resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			logger.L().Debugw("create StatefulSet resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)

		case "DaemonSet":
			obj, ok := item.Resource.(*appsv1.DaemonSet)
			if !ok {
				logger.L().Errorw("转化DaemonSet资源失败", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			_, err = req.ClientSet.AppsV1().DaemonSets(item.Namespace).Create(ctx, obj, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorw("create DaemonSet resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			logger.L().Debugw("create DaemonSet resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)

		case "Job":
			obj, ok := item.Resource.(*batchv1.Job)
			if !ok {
				logger.L().Errorw("转化Job资源失败", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			_, err = req.ClientSet.BatchV1().Jobs(item.Namespace).Create(ctx, obj, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorw("create Job resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			logger.L().Debugw("create Job resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)

		case "CronJob":
			obj, ok := item.Resource.(*batchv1.CronJob)
			if !ok {
				objbet, ok := item.Resource.(*batchv1beta1.CronJob)
				if !ok {
					logger.L().Errorw("转化CronJob资源失败", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
					continue
				}
				_, err = req.ClientSet.BatchV1beta1().CronJobs(item.Namespace).Create(ctx, objbet, metav1.CreateOptions{})
				if err != nil {
					logger.L().Errorw("create CronJob resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
					continue
				}
				logger.L().Debugw("create CronJob resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			_, err = req.ClientSet.BatchV1().CronJobs(item.Namespace).Create(ctx, obj, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorw("create CronJob resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			logger.L().Debugw("create CronJob resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)

		case "Service":
			obj, ok := item.Resource.(*corev1.Service)
			if !ok {
				logger.L().Errorw("转化Service资源失败", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			_, err = req.ClientSet.CoreV1().Services(item.Namespace).Create(ctx, obj, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorw("create Service resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			logger.L().Debugw("create Service resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)

		case "ConfigMap":
			obj, ok := item.Resource.(*corev1.ConfigMap)
			if !ok {
				logger.L().Errorw("转化ConfigMap资源失败", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			_, err = req.ClientSet.CoreV1().ConfigMaps(item.Namespace).Create(ctx, obj, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorw("create ConfigMap resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			logger.L().Debugw("create ConfigMap resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)

		case "Secret":
			obj, ok := item.Resource.(*corev1.Secret)
			if !ok {
				logger.L().Errorw("转化Secret资源失败", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			_, err = req.ClientSet.CoreV1().Secrets(item.Namespace).Create(ctx, obj, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorw("create Secret resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			logger.L().Debugw("create Secret resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)

		case "Namespace":
			obj, ok := item.Resource.(*corev1.Namespace)
			if !ok {
				logger.L().Errorw("转化Namespace资源失败", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			_, err = req.ClientSet.CoreV1().Namespaces().Create(ctx, obj, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorw("create Namespace resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			logger.L().Debugw("create Namespace resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)

		case "PersistentVolume":
			obj, ok := item.Resource.(*corev1.PersistentVolume)
			if !ok {
				logger.L().Errorw("转化PersistentVolume资源失败", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "name", item.Name)
				continue
			}
			_, err = req.ClientSet.CoreV1().PersistentVolumes().Create(ctx, obj, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorw("create PersistentVolume resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "name", item.Name)
				continue
			}
			logger.L().Debugw("create PersistentVolume resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "name", item.Name)

		case "PersistentVolumeClaim":
			obj, ok := item.Resource.(*corev1.PersistentVolumeClaim)
			if !ok {
				logger.L().Errorw("转化PersistentVolumeClaim资源失败", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			_, err = req.ClientSet.CoreV1().PersistentVolumeClaims(item.Namespace).Create(ctx, obj, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorw("create PersistentVolumeClaim resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			logger.L().Debugw("create PersistentVolumeClaim resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)

		case "Role":
			obj, ok := item.Resource.(*rbacv1.Role)
			if !ok {
				logger.L().Errorw("转化Role资源失败", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			_, err = req.ClientSet.RbacV1().Roles(item.Namespace).Create(ctx, obj, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorw("create Role resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			logger.L().Debugw("create Role resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)

		case "RoleBinding":
			obj, ok := item.Resource.(*rbacv1.RoleBinding)
			if !ok {
				logger.L().Errorw("转化RoleBinding资源失败", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			_, err = req.ClientSet.RbacV1().RoleBindings(item.Namespace).Create(ctx, obj, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorw("create RoleBinding resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			logger.L().Debugw("create RoleBinding resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)

		case "ClusterRole":
			obj, ok := item.Resource.(*rbacv1.ClusterRole)
			if !ok {
				logger.L().Errorw("转化ClusterRole资源失败", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "name", item.Name)
				continue
			}
			_, err = req.ClientSet.RbacV1().ClusterRoles().Create(ctx, obj, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorw("create ClusterRole resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "name", item.Name)
				continue
			}
			logger.L().Debugw("create ClusterRole resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "name", item.Name)

		case "ClusterRoleBinding":
			obj, ok := item.Resource.(*rbacv1.ClusterRoleBinding)
			if !ok {
				logger.L().Errorw("转化ClusterRoleBinding资源失败", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "name", item.Name)
				continue
			}
			_, err = req.ClientSet.RbacV1().ClusterRoleBindings().Create(ctx, obj, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorw("create ClusterRoleBinding resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "name", item.Name)
				continue
			}
			logger.L().Debugw("create ClusterRoleBinding resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "name", item.Name)

		case "ServiceAccount":
			obj, ok := item.Resource.(*corev1.ServiceAccount)
			if !ok {
				logger.L().Errorw("转化ServiceAccount资源失败", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			_, err = req.ClientSet.CoreV1().ServiceAccounts(item.Namespace).Create(ctx, obj, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorw("create ServiceAccount resource err", "err", err, "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
				continue
			}
			logger.L().Debugw("create ServiceAccount resource", "key", item.Key, "type", item.ResourcesKind, "version", item.Version, "namespace", item.Namespace, "name", item.Name)
		default:
			return fmt.Errorf("unsupported kind: %s (apiVersion: %s) namespace：%s   name: %s key：%s", item.ResourcesKind, item.Version, item.Namespace, item.Name, item.Key)
		}
	}
	return err
}
